<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JShell测试</title>
    <style>
        div, pre {
            font-family: Consolas, 'Courier New', Courier, monospace;
            display: block;
        }
        a {
            cursor: pointer;
            color: #06f;
        }
        .nc { /* not configurable */
            color: #f00;
        }
        .ne { /* not enumerable */
            color: #0a0;
        }
        .nw { /* not writable */
            color: #00f;
        }
        .ncne {
            color: #f90;
        }
        .ncnw {
            color: #f0f;
        }
        .nenw {
            color: #0cc;
        }
        .ncnenw {
            color: #aaa;
        }
    </style>
</head>
<body>
<div class='nc'>不可删除，但可赋值和遍历</div>
<div class='ne'>不可遍历，但可赋值和删除</div>
<div class='nw'>不可赋值，但可遍历和删除</div>
<div class='ncne'>不可删除和遍历，但可赋值</div>
<div class='ncnw'>不可删除和赋值，但可遍历</div>
<div class='nenw'>不可遍历和赋值，但可删除</div>
<div class='ncnenw'>不可做任何操作</div>
</body>
<script>
function logger(log, style) {
    return function() {
        log.apply(null, arguments);
        // if (arguments[1] == '异常:') debugger;
        var args = [];
        args.push.apply(args, arguments);
        document.body.insertAdjacentHTML('beforeEnd',
            '<pre class="' + style + '">' + args.join(' ') + '</pre>');
    };
}
function descriptor(obj, id, autoOpen, indent) {
    // console.old_dir(obj);
    var parent = id ? document.getElementById(id) : document.body;
    if (!parent) {
        parent = document.body;
        parent.insertAdjacentHTML('beforeEnd', '<div>[' + id + ']</div>');
    }
    indent = indent || (id ? '&nbsp;&nbsp;' : '');
    nextIndent = indent + '&nbsp;&nbsp;';
    var infoMap = Object.getOwnPropertyDescriptors(obj);
    var infoList = [];
    for (var i in infoMap) {
        infoList.push([i, infoMap[i]]);
    }
    infoList.sort(function(a, b) {
        return a[0] < b[0] ? -1 : 1;
    })
    infoList.push(['[__proto__]', {
        value: obj.__proto__,
        configurable: true,
    }]);
    for (var i in infoList) {
        var prop = infoList[i][0];
        var info = infoList[i][1];
        var value = info.value;
        var type = typeof(value);
        var style = (info.configurable ? '' : 'nc') + (info.enumerable ? '' : 'ne') +
            (info.writable ? '' : 'nw');
        var line = '<div>' + indent + '<span class="' +
            style + '">' + prop + '</span>: ';
        if (type == 'object' && value !== null || type == 'function') {
            var cache = descriptor[type];
            if (!cache) {
                cache = [];
                descriptor[type] = cache;
            }
            var index = -1;
            for (var i in cache) {
                if (cache[i] !== value) continue;
                index = i;
                break;
            }
            if (index < 0) {
                index = cache.length;
                cache.push(value);
                id = type + index;
                line = '<div style="overflow:hidden" id="' + id + '"' + line.substr(4) +
                '<a onclick="this.onclick=onoff;console.dir(descriptor.' + type + '[' + index + '], \'' +
                id + '\',' + autoOpen + ',\'' + nextIndent + '\')">[' + type + ' ' + index + ']</a>';
                if (autoOpen) {
                    setTimeout(function(id) {
                        document.getElementById(id).getElementsByTagName('a')[0].click();
                    }, 0, id);
                }
            } else {
                line = line + '[' + type + ' ' + index + ']';
            }
        } else {
            line += type == 'string' ? '"' + value + '"' : value;
        }
        parent.insertAdjacentHTML('beforeEnd', line + '</div>');
    }
}
function onoff() {
    var elem = this.parentElement;
    elem.style.height = elem.style.height ? '' : '19px';
}
console.old_log = console.log;
console.old_info = console.info;
console.old_warn = console.warn;
console.old_error = console.error;
console.old_dir = console.dir;
console.log = logger(console.old_log, 'ncnenw');
console.info = logger(console.old_info, 'nw');
console.warn = logger(console.old_warn, 'ncne');
console.error = logger(console.old_error, 'ne');
console.dir = descriptor;
</script>
<!-- <script src="md5.min.js"></script> -->
<!-- <script src="aes.min.js"></script> -->
<!-- <script src="util.min.js"></script> -->
<!-- <script src="scope.min.js"></script> -->
<script src="jshell.min.js"></script>
<!-- <script src="jshell.js"></script> -->
<script src="test.js"></script>
</html>